#include "stdafx.h"
#include "sgllib.h"
#include "sgldef.h"
#include "sglinfo.h"

SglInfo::SglInfo() :
	m_Error(SGL_SUCCESS)
{
	memset(&m_Info, 0, sizeof(m_Info));
}

SglInfo::~SglInfo()
{

}

PSGLINFO SglInfo::GetHandle(VOID)
{
	return &m_Info;
}

INT SglInfo::GetError(VOID) const
{
	return m_Error;
}

BOOL SglInfo::Open(LPCTSTR pszFile)
{
	if (!pszFile)
	{
		m_Error = SGL_NULLPOINTER;
		return FALSE;
	}

	FILE *pFile = _tfopen(pszFile, _T("rb"));
	if (!pFile)
	{
		m_Error = SGL_ACCESSDENIED;
		return FALSE;
	}

	fseek(pFile, 0, SEEK_END);
	m_Info.dwFileSize = ftell(pFile);

	fseek(pFile, 0, SEEK_SET);
	BOOL bRet = LoadSgl(pFile);

	fclose(pFile);

	if (!bRet)
	{
		ClearSgl();
		return FALSE;
	}

	m_Error = SGL_SUCCESS;
	return TRUE;
}

BOOL SglInfo::Close(VOID)
{
	ClearSgl();

	m_Error = SGL_SUCCESS;
	return TRUE;
}

SglInfo *SglInfo::FromHandle(PSGLINFO pHandle)
{
	return reinterpret_cast<SglInfo *>(pHandle);
}

BOOL SglInfo::LoadSgl(FILE *pFile)
{
	ASSERT(pFile);

	SGL_FILEHEADER sHeader;
	if (!fread(&sHeader, sizeof(sHeader), 1, pFile))
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	if (strcmp(sHeader.szId, SGL_IDENTIFIER))
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	strncpy(m_Info.szId, sHeader.szId, sizeof(m_Info.szId));
	m_Info.dwInfoTabOff = sHeader.dwInfoOff;

	if (fseek(pFile, sHeader.dwInfoOff, SEEK_SET))
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	DWORD dwSubNum;
	if (!fread(&dwSubNum, sizeof(dwSubNum), 1, pFile))
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	if (dwSubNum <= 1UL)
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	m_Info.dwSubNum = dwSubNum;

	LPDWORD pOffTab = new DWORD[dwSubNum];
	PSGLHASH pHashTab = new SGLHASH[dwSubNum];
	BOOL bRet = LoadSgl(pFile, pOffTab, pHashTab);

	delete [] pOffTab;
	delete [] pHashTab;
	return bRet;
}

BOOL SglInfo::LoadSgl(FILE *pFile, LPDWORD pOffTab, PSGLHASH pHashTab)
{
	ASSERT(pFile);

	if (!pOffTab || !pHashTab)
	{
		m_Error = SGL_OUTOFMEMORY;
		return FALSE;
	}

	if (fread(pOffTab, sizeof(DWORD), m_Info.dwSubNum, pFile) != m_Info.dwSubNum)
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	if (fread(pHashTab, sizeof(SGLHASH), m_Info.dwSubNum, pFile) != m_Info.dwSubNum)
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	m_Info.pSubInfo = new PSGLSUB[m_Info.dwSubNum];
	if (!m_Info.pSubInfo)
	{
		m_Error = SGL_OUTOFMEMORY;
		return FALSE;
	}
	memset(m_Info.pSubInfo, 0, sizeof(PSGLSUB) * m_Info.dwSubNum);

	UINT nLast = 0U;
	for (UINT i = 1U; i < m_Info.dwSubNum; i++)
	{
		if (!pOffTab[i])
			continue;

		PSGLSUB pSub = new SGLSUB;
		if (!pSub)
		{
			m_Error = SGL_OUTOFMEMORY;
			return FALSE;
		}
		memset(pSub, 0, sizeof(SGLSUB));

		if (nLast)
			m_Info.pSubInfo[nLast]->dwSize = pOffTab[i] - pOffTab[nLast];

		pSub->dwOffset = pOffTab[i];
		pSub->sHash = pHashTab[i];
		m_Info.pSubInfo[i] = pSub;

		if (fseek(pFile, pOffTab[i], SEEK_SET))
		{
			m_Error = SGL_BADFORMAT;
			return FALSE;
		}

		if (!LoadSub(pFile, pSub))
			return FALSE;
		
		nLast = i;
	}

	if (nLast)
		m_Info.pSubInfo[nLast]->dwSize = m_Info.dwFileSize - pOffTab[nLast];

	return TRUE;
}

BOOL SglInfo::LoadSub(FILE *pFile, PSGLSUB pSubInfo)
{
	ASSERT(pFile && pSubInfo);

	SGL_SUBFILEHEADER sHeader;
	if (!fread(&sHeader, sizeof(sHeader), 1, pFile))
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	pSubInfo->dwFormat = sHeader.dwFormat;

	if (sHeader.dwFormat != SGL_TEXTURE)
		return TRUE;

	SGL_IMAGEHEADER sImgHeader;
	if (!fread(&sImgHeader, sizeof(sImgHeader), 1, pFile))
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	pSubInfo->dwFrameNum = sImgHeader.dwFrameNum;
	if (!sImgHeader.dwFrameNum)
	{
		m_Error = SGL_BADFORMAT;
		return FALSE;
	}

	return TRUE;
}

VOID SglInfo::ClearSgl(VOID)
{
	if (m_Info.pSubInfo)
	{
		for (UINT i = 0U; i < m_Info.dwSubNum; i++)
		{
			PSGLSUB pSub = m_Info.pSubInfo[i];
			if (!pSub)
				continue;

			ClearSub(pSub);
		}

		delete [] m_Info.pSubInfo;
	}

	memset(&m_Info, 0, sizeof(m_Info));
}

VOID SglInfo::ClearSub(PSGLSUB pSubInfo)
{
	delete pSubInfo;
}
